package com.waterwolf.wolfbot;

import java.applet.Applet;
import java.applet.AppletContext;
import java.applet.AppletStub;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Graphics;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;

import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;

import com.waterwolf.wolfbot.debugs.AbstractDebug;
import com.waterwolf.wolfbot.debugs.ClientHookDebug;
import com.waterwolf.wolfbot.debugs.MouseDebug;
import com.waterwolf.wolfbot.internal.Client;
import com.waterwolf.wolfbot.internal.Loader;

public class BasicLoader extends JFrame implements AppletStub {

    public static String _package = "com.waterwolf.wolfbot.internal";

    private static final long serialVersionUID = 7290678744249645100L;
    private String prefix = "";
    private String referer = "http://www.google.com/#hl=en&source=hp&q=runescape&btnG=Google+Search&meta=&aq=f&oq=runescape&fp=324c8a90db775e43";
    private final HashMap<String, String> parameters = new HashMap<String, String>();

    public BasicLoader(final String prefix) {
        try {
            this.prefix = prefix;
            loadParams();
            loadClient();
        } catch (final Exception e) {
            e.printStackTrace();
        }
    }

    private String readPage(final URL url) throws IOException,
            InterruptedException {
        final String s = readPage(url, referer);
        referer = url.toExternalForm();
        return s;
    }

    private String readPage(final URL url, final String referer)
            throws IOException, InterruptedException {
        final URLConnection uc = url.openConnection();
        uc
                .addRequestProperty(
                        "Accept",
                        "text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5");
        uc.addRequestProperty("Accept-Charset",
                "ISO-8859-1,utf-8;q=0.7,*;q=0.7");
        uc.addRequestProperty("Accept-Encoding", "gzip,deflate");
        uc.addRequestProperty("Accept-Language", "en-gb,en;q=0.5");
        uc.addRequestProperty("Connection", "keep-alive");
        uc.addRequestProperty("Host",
                "www.runescape.com[url=http://][/url][url=http://][/url]");
        uc.addRequestProperty("Keep-Alive", "300");
        if (referer != null) {
            uc.addRequestProperty("Referer", referer);
        }
        uc
                .addRequestProperty(
                        "User-Agent",
                        "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.8.0.6) Gecko/20060728 Firefox/1.5.0.6");
        final DataInputStream di = new DataInputStream(uc.getInputStream());
        final byte[] buffer = new byte[uc.getContentLength()];
        di.readFully(buffer);
        di.close();
        Thread.sleep(250 + (int) Math.random() * 500);
        return new String(buffer);
    }

    private final void loadParams() throws MalformedURLException, IOException,
            InterruptedException {
        final String html = readPage(new URL("http://" + prefix
                + ".runescape.com/a2,m0,j0,o0"));
        try {
            final Pattern regex = Pattern.compile(
                    "<param name=([^\\s]+)\\s+value=\"{0,1}(.*?)\"{0,1}>",
                    Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE);
            final Matcher regexMatcher = regex.matcher(html);
            while (regexMatcher.find())
                if (!parameters.containsKey(regexMatcher.group(1))) {
                    parameters
                            .put(regexMatcher.group(1), regexMatcher.group(2));
                }
        } catch (final PatternSyntaxException ex) {
            ex.printStackTrace();
        }
    }

    public static Client clientz = null;

    private static AbstractDebug[] debugs = new AbstractDebug[] {
            new ClientHookDebug(), new MouseDebug() };

    public static JCheckBox debugToggle = new JCheckBox("Enable debugs");

    public static void getBotGraphics(final Graphics input) {

        if (clientz == null || !debugToggle.isSelected())
            return;

        int i = 0;

        for (final AbstractDebug ad : debugs) {
            i = ad.paint(clientz, input, i);
        }
    }

    static HashMap<String, byte[]> classes = new HashMap<String, byte[]>();

    private final void loadClient() throws InstantiationException,
            IllegalAccessException, ClassNotFoundException, IOException {

        final HookLoader hl = new HookLoader();

        try {
            //final File fjar = new File("archive/injected/injected_client_latest.jar");
            final File fjar = new File("game.jar");
            final JarFile rsJar = new JarFile(fjar);

            final Enumeration<JarEntry> entries = rsJar.entries();
            while (entries.hasMoreElements()) {
                final JarEntry entry = entries.nextElement();
                String name = entry.getName();
                if (name.endsWith(".class")) {
                    name = name.substring(0, name.length() - 6).replace('/',
                            '.');
                    
                    byte[] wat = load(rsJar.getInputStream(entry));
                    
                    wat = hl.hack(wat);
                    
                    classes.put(name, wat);
                }
            }

        } catch (final IOException e) {
            e.printStackTrace();
        }

        final MyClassLoader classLoader = new MyClassLoader(new JarFile(
                "loader.jar"));
        final Applet client = (Applet) classLoader.loadClass("loader")
                .newInstance();
        client.setStub(this);
        client.init();
        client.start();

        final Loader loader = (Loader) client;
        Applet app;
        while ((app = loader.getApplet()) == null) {
            try {
                Thread.sleep(100);
            } catch (final InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }

        clientz = (Client) app;
        
        System.out.println(clientz.getLocalPlayer());

        System.out.println("Applet succesfully loaded and casted to Client");

        JPopupMenu.setDefaultLightWeightPopupEnabled(false);
        final JPanel backPanel = new JPanel(new BorderLayout());
        backPanel.setPreferredSize(new Dimension(768, 560));
        setPreferredSize(new Dimension(768, 658));
        backPanel.add(client);
        add(backPanel, BorderLayout.CENTER);
        add(debugToggle, BorderLayout.NORTH);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setTitle("WaterwolfBot");
        setSize(769, 561);
    }

    private byte[] load(final InputStream is) throws IOException {
        final ByteArrayOutputStream os = new ByteArrayOutputStream();
        final byte[] buffer = new byte[4096];
        int n;
        while ((n = is.read(buffer)) != -1) {
            os.write(buffer, 0, n);
        }
        return os.toByteArray();
    }

    @Override
    public void appletResize(final int width, final int height) {
        // TODO Auto-generated method stub

    }

    @Override
    public AppletContext getAppletContext() {
        throw new UnsupportedOperationException();
    }

    @Override
    public URL getCodeBase() {
        try {
            return new URL("http://" + prefix + ".runescape.com/");
        } catch (final Exception e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public URL getDocumentBase() {
        return getCodeBase();
    }

    @Override
    public String getParameter(final String name) {
        return parameters.get(name);
    }

    static ClientClassLoader ccl = null;

    public static void setClassloader(final ClientClassLoader ccl) {
        BasicLoader.ccl = ccl;
        System.out.println("ccl instintiated");
    }

    /**
     * @param args
     */
    public static void main(final String[] args) {

        final File loader = new File("loader.jar");

        if (!loader.exists()) {
            System.out.println("Loader.jar doesn't exist, downloading..");

            try {

                final ReadableByteChannel rbc = Channels.newChannel(new URL(
                        "http://world1.runescape.com/loader.jar").openStream());
                final FileOutputStream fos = new FileOutputStream(loader);
                fos.getChannel().transferFrom(rbc, 0, 1 << 24);
            } catch (final IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }

        final File game = new File("game.jar");

        if (!game.exists()) {
            System.out.println("Game.jar doesn't exist, downloading..");

            try {

                final ReadableByteChannel rbc = Channels.newChannel(new URL(
                        "http://world1.runescape.com/runescape.jar")
                        .openStream());
                final FileOutputStream fos = new FileOutputStream(game);
                fos.getChannel().transferFrom(rbc, 0, 1 << 24);
            } catch (final IOException e) {
                e.printStackTrace();
            }
        }

        try {
            new BasicLoader("world106").setVisible(true);
        } catch (final Exception e) {
            throw new RuntimeException(e);
        }
    }

}
